#include "bootpack.h"
#include "package.h"
/*
struct DHCP_DISCOVER{
    unsigned char op;
    unsigned char htype;
    unsigned char hlen;
    unsigned char hops;
    unsigned int xid;
    short secs;
    short flag;
    long ciaddr;
    long yiaddr;
    long siaddr;
    long giaddr;
    unsigned char[16] chaddr;
    unsigned char[64] sname;
    unsigned char[128] file;
    struct DHCP_OPTIONS *options;
};
struct DHCP_OPTIONS{
    unsigned char type;
    unsigned char length;
    unsigned char *value;
};

*/
/*
void init_dhcp_options(struct MEMMAN *memman,struct DHCP_OPTIONS *options){
    //struct DHCP_OPTIONS options_array[7]
    options=(unsigned char *)memman_alloc_4k(memman,64);
        {51,1,{1}},
        {61,7,{1,0x52,0x54,0x00,0x12,0x34,0x56}},
        {50,4,{192,168,1,5},
        {12,15,{'z','m','m'}},
        {60,8,{'r','l','k'}},
        {55,12,{1,25,3,6,44,46,47,31,33,121,249,43}},
        {255,255,{}},
    };
}
*/

void init_message_package(DHCP_MESSAGE * dd,DHCP_INFO * dhcp_info){
    dd->op=1;
    dd->htype=1;
    dd->hlen=6;
    dd->hops=0;
    dd->xid=0x83208856;
    dd->secs=0;
    dd->flag=0;
    dd->ciaddr=dhcp_info->client_ip_addr;
    dd->yiaddr=0;
    dd->siaddr=0;
    dd->giaddr=0;
    dd->chaddr[5]=GetRegisterValue(1,6);
    dd->chaddr[4]=GetRegisterValue(1,5);
    dd->chaddr[3]=GetRegisterValue(1,4);
    dd->chaddr[2]=GetRegisterValue(1,3);
    dd->chaddr[1]=GetRegisterValue(1,2);
    dd->chaddr[0]=GetRegisterValue(1,1);
    int i;
    //dd->sname=(unsigned char *)memman_alloc_4k(memman,64);
    for(i=0;i<64;i++)
        dd->sname[i]=0;
    for(i=0;i<128;i++)
        dd->file[i]=0;
    //dd->file=(unsigned char *)memman_alloc_4k(memman,128);
    dd->magic_cookie[0]=0x63;
    dd->magic_cookie[1]=0x82;
    dd->magic_cookie[2]=0x53;
    dd->magic_cookie[3]=0x63;
    //dd->options=options;
    uchar *cip = (uchar *)(&(dhcp_info->client_ip_addr));
    unsigned char options[44]={
        0x35,0x01,dhcp_info->message_type,//3
        61,7,1,GetRegisterValue(1,1),GetRegisterValue(1,2),GetRegisterValue(1,3),GetRegisterValue(1,4),GetRegisterValue(1,5),GetRegisterValue(1,6),//9
        50,4,cip[0],cip[1],cip[2],cip[3],//6
        12,3,'z','m','m',//5
        60,3,'r','l','k',//5
        55,14,1,3,6,15,31,33,43,44,46,47,119,121,249,252//16
    };
    
    for(i=0;i<44;i++){
        dd->options[i]=options[i];
    }
    for(i=0;i<10;i++){
        dd->end[i]=0x00;
    }
    dd->end[0]=0xff;


}

short calculate_checksum(short* buffer, int bytes)
{
    short checksum = 0;
    short * end = buffer + bytes;

    // odd bytes add last byte and reset end
    if (bytes % 2 == 1) {
        end = buffer + bytes - 1;
        checksum += (*end) << 8;
    }

    // add words of two bytes, one by one
    while (buffer < end) {
        checksum += buffer[0] << 8;
        checksum += buffer[1];
        buffer += 2;
    }

    // add carry if any
    short carray = checksum >> 16;
    while (carray) {
        checksum = (checksum & 0xffff) + carray;
        carray = checksum >> 16;
    }

    // negate it
    checksum = ~checksum;

    return checksum & 0xffff;
}

void init_ip_package(IP_HEADER * header){
    /*
    unsigned char ip_and_headlength;
    unsigned char service_level;
    short length;
    short identify;
    short label_and_offset;
    unsigned char    ttl;
    unsigned char protocal;
    short head_checksum;
    long src_ip;
    long dst_ip;
    struct UDP_PACKAGE udp;
    */
    header->ip_and_headlength=0x45;
    header->service_level=0x00;
    //header->length=(sizeof(IP_PACKAGE)&0xff00)>>8 + (sizeof(IP_PACKAGE)&0xff)<<8;
    header->length=hxl(sizeof(IP_PACKAGE)-4);
    //header->length=sizeof(IP_PACKAGE)-4;

    header->identify=0x3333;
    header->label_and_offset=hxl(0x0<<14);// 不分段
    header->ttl=0x80;//生存时间设置为最大
    header->protocal=17;// 协议号是10进制的
    header->head_checksum=0;
    header->src_ip=0x00000000;
    header->dest_ip=0xffffffff;
}
void init_mac_header(MAC_PACKAGE *mac){
    /*unsigned char dest_mac[6];
    unsigned char src_mac[6];
    short type;
    struct IP_PACKAGE ip;
    */
    unsigned char dest_mac[6]={0xff,0xff,0xff,0xff,0xff,0xff};
    unsigned char src_mac[6]={0x52,0x54,0x00,0x12,0x34,0x56};
    int i;
    for(i=0;i<6;i++){
        mac->header.dest_mac[i]=dest_mac[i];
        mac->header.src_mac[i]=GetRegisterValue(1,i+1);
    }
    mac->header.pre=0xff;
    mac->header.protocal=0x0008;
}
int show_package(unsigned char *buf_back,struct BOOTINFO *binfo,unsigned char * p,int length,int back_row,char * name,unsigned char * s){
    //unsigned char * p=(unsigned char*)(&(mac_p->ip));
    //sprintf(s,"ip:");
    //unsigned char s[40];
    int i;
    sprintf(s,"[%d]-[%d]-%s",back_row,length,name);
    int length_show=length;
    if(length_show>30)
        length_show=30;
    for(i=0;i<length_show;i++){
        sprintf(s,"%s%02x",s,p[i]);
    }
    sprintf(s,"%s<--->",s);
    for(i=0;i<1;i++){
        sprintf(s,"%s%02x",s,p[length-1-i]);
    }

    putfonts8_asc(buf_back, binfo->scrnx, 50, 350+back_row*16, COL8_FFFFFF, s);
    back_row++;
    return back_row;
}

void analysis_buff(FORSHOWINFO forshow,uchar *recv,uchar *s2){
    int i=-4;
    strshow("mac header:");
    sprintf(s2,"DEST MAC:%02x-%02x-%02x-%02x-%02x-%02x",recv[i+4],recv[i+5],recv[i+6],recv[i+7],recv[i+8],recv[i+9]);
    sprintf(s2,"%s,SRC MAC:%02x-%02x-%02x-%02x-%02x-%02x",s2,recv[i+10],recv[i+11],recv[i+12],recv[i+13],recv[i+14],recv[i+15]);
    //sprintf(s2,"%s,L:%d ",s2,*((unsigned short *)(recv+i+2)));
    strshow(s2);
                    
    // ip start at 18
    strshow("ip  header:");
    //sprintf(s2,"L:%d",*((unsigned char *)(recv+i+21))+(*(recv+i+20)<<8));
    sprintf(s2,"L:%d",(*(recv+i+21)) | (*(recv+i+20)<<8) );
    // 分段:ip_start+ 4,5,6,7
    // TTL: 8
    // Protocal:9
    uchar protocal = *(recv+i+27);
    sprintf(s2,"%s,PROTO:%d",s2,protocal);
    //buffshow(recv+i+27,1);// IP上层协议
    //Checksum: 10,11
    // src ip:12,13,14,15
    //buffshow(recv+i+30,4); src ip 
    // dest ip:16,17,18,19
    //buffshow(recv+i+34,4); dest ip
    sprintf(s2,"%s,SRC IP:%d.%d.%d.%d",s2,recv[i+30],recv[i+31],recv[i+32],recv[i+33]);
    sprintf(s2,"%s,DEST IP:%d.%d.%d.%d",s2,recv[i+34],recv[i+35],recv[i+36],recv[i+37]);
    strshow(s2);
    if(protocal==17){ // 如果是17，表明需要用UDP协议去解析数据
        strshow("udp header:");
        //sprintf(s2,"SRC PORT:%d",*((unsigned char *)(recv+i+39))+(*(recv+i+38)<<8));
        //sprintf(s2,"%s,DEST PORT:%d",s2,*((unsigned char *)(recv+i+41))+(*(recv+i+40)<<8));
        sprintf(s2,"SRC PORT:%d",hxl(*((unsigned short *)(recv+i+38))));
        sprintf(s2,"%s,DEST PORT:%d",s2,hxl(*((unsigned short *)(recv+i+40))));
        //length_udp=*((unsigned char *)(recv+i+43))+(*(recv+i+42)<<8);
        unsigned short length_udp=hxl(*((unsigned short *)(recv+i+42)));
        sprintf(s2,"%s,L:%d",s2,length_udp);
        strshow(s2);

        strshow("udp data:");
        buffshow(recv+i+46,length_udp-8);
    }
}
void analysis_struct(FORSHOWINFO *forshow,uchar *recv,uchar *s2,int start_index){  
    MAC_HEADER * mac_header = (MAC_HEADER *)(recv+start_index);
    sprintf(s2,"row:%d,%d",forshow->curr_row,forshow->end_row);
    strshow(s2);
    strshow("mac header:dest,src,protocal ");
    buffshow(mac_header->dest_mac,6);
    buffshow(mac_header->src_mac,6);
    buffshow(&(mac_header->protocal),2);
    
    IP_HEADER * ip_header = (IP_HEADER *)(mac_header+1);
    strshow("ip header:type,headlength,ttl,protocal,src_ip,dest_ip,identify,label_and_offset,length");
    buffshow(&(ip_header->ip_and_headlength),1);
    buffshow(&(ip_header->protocal),1);
    forshow->is_hex=0;// decimal system
    buffshow(&(ip_header->src_ip),4);
    buffshow(&(ip_header->dest_ip),4);
    forshow->is_hex=1;// hex system
    buffshow(&(ip_header->identify),2);
    buffshow(&(ip_header->label_and_offset),2);
    forshow->is_hex=0;// decimal system
    buffshow(&(ip_header->length),2);
    forshow->is_hex=1;// decimal system
    

    UDP_HEADER * udp_header= (UDP_HEADER *)(ip_header +1);
    strshow("udp header:src_port dest_port length checksum");
    forshow->is_hex=0;// decimal system
    buffshow(&(udp_header->src_port),2);
    buffshow(&(udp_header->dest_port),2);
    buffshow(&(udp_header->length),2);
    forshow->is_hex=1;// decimal system
    buffshow(&(udp_header->check_sum),2);

    DHCP_MESSAGE * dhcp_message = (DHCP_MESSAGE *)(udp_header+1);
    DHCP_INFO dhcp_info_recv={0,0,0,0,0,0,0,0,0};
    dhcp_options_ana(dhcp_message->options,&dhcp_info_recv);
    uchar s3[20];
    switch(dhcp_info_recv.message_type){
        case 1:
            sprintf(s3,"[DISCOVER]");
            break;
        case 2:
            sprintf(s3,"[OFFER]");
            break;
        case 3:
            sprintf(s3,"[REQUEST]");
            break;
        case 5:
            sprintf(s3,"[ACK]");
            break;
        case 6:
            sprintf(s3,"[NAK]");
            break;

        default:
            sprintf(s3,"[OTHER]");
    }
    sprintf(s2,"DHCP %s message:ci,yi,si,gi addr options,dhcp_type",s3);
    strshow(s2);
    forshow->is_hex=0;
    buffshow(&(dhcp_message->ciaddr),4);
    buffshow(&(dhcp_message->yiaddr),4);
    buffshow(&(dhcp_message->siaddr),4);
    buffshow(&(dhcp_message->giaddr),4);
   

    //buffshow(dhcp_message->options,dhcp_info_recv.length);
    strshow("dhcp_options:server_identifier,router,subnet_mask,domain_name_server,lease_time,length");
                            /*
    uchar message_type;
    long client_ip_addr;
    int length;
    long server_identifier;
    long lease_time;
    long subnet_mask;
    long router;
    long domain_name_server;
    uchar *domain_name;
    */
    buffshow(&(dhcp_info_recv.server_identifier),4);
    buffshow(&(dhcp_info_recv.router),4);
    buffshow(&(dhcp_info_recv.subnet_mask),4);
    buffshow(&(dhcp_info_recv.domain_name_server),4);
    buffshow(&(dhcp_info_recv.lease_time),4);
    buffshow(&(dhcp_info_recv.length),4);



    forshow->is_hex=1;

}
int dhcp_options_ana(uchar *options,DHCP_INFO * dhcp_info){
    /*
    uchar message_type;
    long client_ip_addr;
    int length;
    long server_identifier;
    long lease_time;
    long subnet_mask;
    long router;
    long domain_name_server;
    uchar *domain_name;
    */
    int i=0;
    int length=1;
    int tmp_len=1;
    for(i=0;i<100;i++){

        switch(*(options+length-1)){
            case 1:// subnet mask
                dhcp_info->subnet_mask=*((long *)(options+length+1));
                break;
            case 2:
                break;
            case 3:// router
                dhcp_info->router=*((long *)(options+length+1));
                break;
            case 4:
                break;
            case 5:
                break;
            case 6:// domain name server
                dhcp_info->domain_name_server=*((long *)(options+length+1));
                break;
            case 15: // domain name
                break;
            case 51: // ip addr lease time
                dhcp_info->lease_time=*((long *)(options+length+1));
                break;
            
            case 53:
                dhcp_info->message_type=*(options+length+1);
                //return dhcp_info->message_type;
                break;
            case 54: // server identifier
                dhcp_info->server_identifier=*((long *)(options+length+1));
                break;
            
            default:
                break;

        }
        tmp_len=*(options+length);
        length=length+tmp_len+2;
        if((*(options+length))==0 && (*(options+length-1))==0xff){
            length=length-2;
            break;
        }

    }
    dhcp_info->length=length+1;
   
    return 0;
}
int src_port_filter(FORSHOWINFO * forshow,uchar *recv,int start_index,short port){
    MAC_HEADER * mac_header = (MAC_HEADER *)(recv+start_index);
    if(mac_header->protocal==hxl(0x0800)){
        IP_HEADER * ip_header = (IP_HEADER *)(mac_header+1);
        if(ip_header->protocal==0x11){
            UDP_HEADER * udp_header= (UDP_HEADER *)(ip_header +1);
            if(udp_header->src_port==hxl(port)){
                return 1;
            }
        }
    }
    return 0;

}
/*
int dhcp_message_filter(uchar *recv,int start_index){
    MAC_HEADER * mac_header = (MAC_HEADER *)(recv+start_index);
    if(mac_header->protocal==hxl(0x0800)){
        IP_HEADER * ip_header = (IP_HEADER *)(mac_header+1);
        if(ip_header->protocal==0x11){
            UDP_HEADER * udp_header= (UDP_HEADER *)(ip_header +1);
            DHCP_MESSAGE * dm = (DHCP_MESSAGE *)(udp_header+1);
            return dhcp_options_ana(dm->options);
        }
    }
    return 0;
}
*/
int get_dhcp_message(uchar *recv,int start_index){
    MAC_HEADER * mac_header = (MAC_HEADER *)(recv+start_index);
    if(mac_header->protocal==hxl(0x0800)){
        IP_HEADER * ip_header = (IP_HEADER *)(mac_header+1);
        if(ip_header->protocal==0x11){
            UDP_HEADER * udp_header= (UDP_HEADER *)(ip_header +1);
            DHCP_MESSAGE * dm = (DHCP_MESSAGE *)(udp_header+1);
            return dm;
        }
    }
    return 0;
}



MAC_PACKAGE * create_dhcp_pacakge(struct MEMMAN *memman,DHCP_INFO* dhcp_info){
    
    MAC_PACKAGE *mac_p= (MAC_PACKAGE *) memman_alloc_4k(memman, sizeof(MAC_PACKAGE));

     // MAC header
    init_mac_header(mac_p);
    // IP header
    init_ip_package(&((mac_p->ip).header));
    mac_p->ip.header.head_checksum=calculate_checksum((unsigned short *)(&(mac_p->ip.header)),sizeof(mac_p->ip.header)/2);
    
    // UDP header
    mac_p->ip.udp.header.src_port=hxl(68);
    mac_p->ip.udp.header.dest_port=hxl(67);
    mac_p->ip.udp.header.length=hxl(sizeof(mac_p->ip.udp)-4);
    //mac_p->ip.udp.lenth=sizeof(mac_p->ip.udp)-4;
    mac_p->ip.udp.header.check_sum=0;

    struct UDP_PERSDO_PACKAGE *udp_persdo=(struct UDP_PERSDO_PACKAGE *)memman_alloc_4k(memman,sizeof(struct UDP_PERSDO_PACKAGE));
    udp_persdo->src_ip = 0x00000000;
    udp_persdo->dest_ip = 0xffffffff;
    udp_persdo->zeros=0x00;
    udp_persdo->protocal = 17;
    udp_persdo->length = sizeof(struct UDP_PERSDO_PACKAGE);
    
    
    // DHCP message header
    init_message_package(&(mac_p->ip.udp.message),dhcp_info);
    //init_message_package(&(mac_p->ip.udp.message));
    udp_persdo->message=mac_p->ip.udp.message;
    mac_p->ip.udp.header.check_sum = calculate_checksum((short *)udp_persdo, sizeof(*udp_persdo)/2);
    // 释放UPD伪包的内存
    memman_free(memman,&(udp_persdo),sizeof(*(udp_persdo)));
    return mac_p;
}
